#include "StdAfx.h"
#include ".\ctimer.h"
#include <cmath>	// for fabs



//If we try and update with a BitBlt over 200 times per second, the animation
//has an odd jump in it every few hundred updates.  To prevent this, we don't 
//allow the counter to run so overly fast, and make it spin in a while loop in
//Tick() if it would give a timestep of, say, less than a hundredth, which is
//more than fast enough for a video animation.  0.005 or even 0.0025 are OK too,
//but the jerkiness is present at 0.001.
//We also set a m_maxDT field because when you get less than ten or so updates per
//second the program gets too jerky if we let the dt returned by updage() reflect 
//the "true" dt per update.  For a really slow simulation, in other words, we
//give up on real time and pretend we have 20 updates per second.
#define START_MINDT 0.01
#define START_MAXDT 0.05

//As we like to have the updatesPerSecond as information to show the user,
//it shouldn't flicker between different values all the time, as it tends to do,
//what with Windows doing things in the background during some cycles but not
//during others.  To prevent the flicker, we use a rolling average of the 
//values.  Empirically, I find that 60 is about the lowest average span which
//stabilizes. Note that the use of a rolling average means that it takes the
//values to home in on something stable, but that's ok and kind of cool to 
//watch.  The static fixed array gets initialized to all 0s, so the startup
//is a smooth creep upward.
#define ROLLING_AVERAGE_SPAN 60

//Comment FORCE_NOT_HIGHRESOLUTION_PERFORMANCE_COUNTER in, for testing, to prevent 
//the High-resolution Performance Counter being used, so you can test the crappy 
//lo-res clock() or timeGetTime() functions.
//#define FORCE_NOT_HIGHRESOLUTION_PERFORMANCE_COUNTER 

//If USE_CLOCK is defined, use clock() function, otherwise use timeGetTime().
//They seem to have about the same temporal resolution (minimum time interval
//measured), and clock() is perhaps more portable.  Note that timeGetTime uses
//the multimedia library. timeGetTime returns the time in milliseconds, it does
//not have a resolution of one millisecond, that is, if you keep calling it, it
//might return a different value only after 6 or 43 milliseconds.  The clock()
//function is similar, but its units aren't guaranteed to be any special time
//length.  You use the CLOCKS_PER_SECOND defined in time.h to convert clock values
//into milliseconds.  As it happens, CLOCKS_PER_SECOND actually is 1000 in the
//current Visual C++ implmenetation, so clock really is about the same as 
//timeGetTime.  I'm not positive if the two have the same minimum jump size to 
//their tick, I haven't checked it closely. Debugging timer code is a bit 
//troublesome as when you're stopping for the debugger, the clocks keep running,
//so you see atypically long values of _dt in here.
#define USE_CLOCK
#ifndef USE_CLOCK
#include <mmsystem.h> //for timeGetTime.  Must also link to winmm.lib
#pragma comment(lib,"winmm.lib")
#endif //USE_CLOCK

//I have LargeIntegerToDouble function because a LARGE_INTEGER is a 64-bit "union"
//type that can be viewed either as holding a single 64 bit integer field called
//QuadPart, or as holding two 32 bit fields called LowPart and HighPart.  The 
//QuadPart field only works if my chip supports 64 bit integers, but perhaps some 
//pre-Pentium chips may not. So I write a _largeIntegerToDouble function to munge 
//a LARGE_INTEGER into a double, and have a ASSUME_64BIT switch so it works on a 
//pure 32-bit machine. Probably this isn't necessary, though, as we only use the 
//LARGE_INTEGER on a machine which supports High Performance counter, which means 
//it's modern, so it would be safe to comment ASSUME_64BIT in.  But we are only 
//likely to need the _largeIntegerToDouble  function once per update anyway, so 
//the speed isn't a real issue, so why not be safe.
#define ASSUME_64BIT

// When I do my update method, it may happen that not very much time has elapsed 
// since the last call.  It's not a good idea to return very small dt from update 
// as if you try and update a monitor more often than its refresh rate (typically 
// 60, 75, or 80 updates a second) then the display will look screwed up.  Another 
// issue is that if you're using the clock or the timeGetTime function, it is a 
// coarse measure of time and won't actually measure less than something like 6 
// millisecond time clicks and can return a spurious 0.  So what we need to do is 
// to not allow update to return a dt less than our _mindt size, which should be 
// at the smallest something like 0.01 seconds (100 updates per second).  This 
// means we have to kill some time inside update.  The safest way to do this by 
// simply running around and around a while loop till enough time had elapsed.  
// This has the bad effect of sucking up a lot of processor time, so that the app 
// won't share as well as it could in multitasking situations.  To some extent this 
// doesn't matter, if our app pauses when it loses the focus. I experimented with 
// using the ::Sleep function and put the execution thread to sleep for a few 
// milliseconds.  This would seem to support multitasking better than hoggin the 
// processor with a while loop.  But I found that if I use the Sleep method, then 
// often an app will cause the machine not to be able to run any other apps.  The 
// app keeps running fine, but if you try and open another app, it won't open. And 
// if you close the app, all other apps are still frozen; the only way out is to 
// a hard on/off switch reboot.  This bug was particularly hard to pinpoint as it 
// doesn't happen all the time, or right away.  Typically it would happen only after 
// the app had run for some time.  But if I let it run long enough (15 minutes to 
// half an hour), then it would always arise, that is, I would be unable to open 
// up another other apps besides my app, and this bad beavior would continue even 
// after the app was closed.  I don't know why this behavior occurs. This note from 
// the Sleep documentation may be relevant.  "If you have a thread that uses Sleep 
// with infinite delay, the system will deadlock."  For now, don't use Sleep. 
//#define USESLEEP //DON'T comment this in!




Timer::Timer(void)
:	m_dt(START_MINDT),	//Just to put a non-zero number in here.
	m_mindt(START_MINDT),	
	m_maxdt(START_MAXDT),
	m_highPerformanceFlag(TRUE),
	m_startUpdate(0),
	m_finish(0),
	m_startTimer(0)
{

	m_cyclesPerSecond = double(90000000UL); //90 MegaHerz, just for a default
	m_lgintStartUpdate.LowPart = m_lgintStartUpdate.HighPart = 0;
	m_lgintStartTimer.LowPart = m_lgintStartTimer.HighPart = 0;
	m_lgintFinish.LowPart = m_lgintFinish.HighPart = 0;

	LARGE_INTEGER cyclesPerSecond;

#ifndef FORCE_NOT_HIGHRESOLUTION_PERFORMANCE_COUNTER
	if (m_highPerformanceFlag = ::QueryPerformanceFrequency(&cyclesPerSecond))
	{
		m_cyclesPerSecond = LargeIntToDouble(cyclesPerSecond);
	}
#endif

	Reset();
}



//////////////////////////////////////////////////////////////////////////
// convert
double Timer::LargeIntToDouble(LARGE_INTEGER lg)
{
#ifndef ASSUME_64BIT
	double lowpart, highpart;
	lowpart = double(lg.LowPart);
	highpart = double(lg.HighPart);
	highpart *= (double(0xFFFFFFFFUL)+1.0); //This is a way to say 2^32.
	//quadpart = highpart + lowpart;
	return highpart + lowpart;
#else	//assume 64 bit
	return double(lg.QuadPart);	
#endif
}


//////////////////////////////////////////////////////////////////////////
// Won't let you set it to 0.0 or above m_maxdt.
void Timer::SetMinDt(double mindt)
{
	if (mindt<=0)
		return;
	if (mindt > m_maxdt)
		mindt = m_maxdt;
	m_mindt = mindt;
}

//////////////////////////////////////////////////////////////////////////
// Won't let you set it below _mindt.
void Timer::SetMaxDt(double maxdt)
{
	if (maxdt < m_mindt)
		maxdt = m_mindt;
	m_maxdt = maxdt;
}



//////////////////////////////////////////////////////////////////////////
// 
double Timer::UpdatesPerSecond() const
{
	static double ups[ROLLING_AVERAGE_SPAN];
	double ups_sum = 0.0;

	for (int i=ROLLING_AVERAGE_SPAN - 1; i>0 ; i--)
	{
		ups[i] = ups[i-1];
		ups_sum += ups[i];
	}

	if (fabs(m_dt)<m_mindt) //Redundant check to prevent division by 0
		ups[0] = 1/m_mindt;
	else
		ups[0] =  1.0/m_dt; 
	return (ups_sum + ups[0])/ROLLING_AVERAGE_SPAN;
}


//////////////////////////////////////////////////////////////////////////
void Timer::Reset()
{
	if (m_highPerformanceFlag)
	{
		::QueryPerformanceCounter(&m_lgintStartUpdate);
		m_lgintFinish = m_lgintStartTimer = m_lgintStartUpdate;
	}
	else
	{
#ifdef USE_CLOCK
		m_startUpdate = clock();
#else
		m_startUpdate = timeGetTime();
#endif
		m_finish = m_startTimer = m_startUpdate;
	}
}


#ifdef USE_SLEEP

#else // dont USE_SLEEP




//////////////////////////////////////////////////////////////////////////
// returns elapsed seconds between last Tick call and this Tick call.
// it waits until the elapsed seconds are >= minDT
double Timer::Tick()
{
	double dt=0;

#ifdef SHOW_SPIN
	int spinIterations=0;
#endif
	
	if (m_highPerformanceFlag)
	{
		while (dt<m_mindt)	// Don't try to update overly fast.
		{
			::QueryPerformanceCounter(&m_lgintFinish);
			dt = (LargeIntToDouble(m_lgintFinish) - 
				LargeIntToDouble(m_lgintStartUpdate)) / m_cyclesPerSecond;

#ifdef SHOW_SPIN
			spinIterations++;
			if (dt >= m_mindt) 
				TRACE("highperformance spiniterations = %d, dt = %f\n", 
					spinIterations, dt);
#endif
		}
		m_lgintStartUpdate = m_lgintFinish;
	}
	else
	{
		/*The  lo-res time functions often haven't clicked yet and you get a
		false read of a _dt of 0.0, which means no update is actually done and
		a misleading value gets into the updatesPerSecond, so we just 
		wait for the  clock to tick. Instead of ticking in increments of one,
		these clocks tick in increments of 6 or 21 or something. I can measure 
		this by using the spiniterations counter, if I like.*/
		while (dt<m_mindt) 
		{
#ifdef USE_CLOCK
			m_finish = clock();
			dt = double(m_finish-m_startUpdate)/CLOCKS_PER_SEC;
#else //USE_CLOCK
			m_finish = timeGetTime();
			dt = double(m_finish-m_startUpdate)/1000.0;
#endif //USE_CLOCK

#ifdef SHOW_SPIN
			spinIterations++;
			if (dt >= m_mindt)	// if (dt != 0.0) will do the same thing here, 
									//as dt is steadily 0 before jumping to 0.16
				TRACE("clock spiniterations = %d, dt = %f\n", 
				spinIterations, dt);
#endif // SHOW_SPIN
		}
		m_startUpdate = m_finish;		
	}
	m_dt = dt;
	return __min(m_dt,m_maxdt);
}

#endif //USE_SLEEP



//////////////////////////////////////////////////////////////////////////
// returns the elapsed seconds between the last Reset() and the 
// last Tick() calls
double Timer::ElapsedSeconds()
{
	if (m_highPerformanceFlag)
	{
		return ( LargeIntToDouble(m_lgintFinish) - 
			LargeIntToDouble(m_lgintStartTimer))/m_cyclesPerSecond;
	}
	else
	{
#ifdef USE_CLOCK
		return  double(m_finish - m_startTimer)/CLOCKS_PER_SEC;
#else //USE_CLOCK
		return  double(m_finish - m_startTimer)/1000.0;
#endif //USE_CLOCK
	}
}

